package tsing.javase.redis.controller;

import cn.hutool.core.util.StrUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import tsing.javase.redis.RedisUtil;
import tsing.javase.redis.RedissonUtil;

import java.util.concurrent.TimeUnit;

/**
 * @Date 2024/1/26 13:35
 *
 * redis 同步锁使用示例1  对应接口1
 * 使用场景：在并发的场景下，相同的请求同时请求多次，会导致处理多次，解决方法：增加redis同步锁
 *  redis同步锁实现思路：
 *      原理是：redis的setNx方法，  key:为请求的参数;value:前缀+当前请求时间戳+uuid
 *      当判断key存在时，结束；
 *      删除key时，判断value是否相同，相同才允许删除
 *
 *
 * redis 同步锁使用示例2 对应接口2
 *  当并发请求时，谁拿到了锁，则开始执行业务逻辑；而另一个则会等待锁释放
 *  缺点：当redis锁超时时，业务逻辑还未执行完成，则会导致无法预料的同步问题
 *  示例2：适用于处理时间 < 锁超时时间的情景下
 *
 *
 * 示例1 和示例2 的区别：示例1获取不到锁资源，不会进入逻辑；而示例2会等待 锁释放
 */
@RestController
@RequestMapping("/redis")
public class RedisController {

    @Autowired
   private RedisUtil redisUtil;

    @RequestMapping("/test")
    public String redisTest(){
        /*String timeStamp = System.currentTimeMillis()+"";
        String lock = timeStamp+ UUID.fastUUID();*/
        String lock = "1";
        String key = "prefix"+"userid"+"orderId";
        try {
            boolean b = redisUtil.setNx(key, lock, 20);
            if (!b) {
                return "已存在相同的订单结束";
            }
            // 执行逻辑
            Thread.sleep(5000);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            String value = (String)redisUtil.get(key);
            if(StrUtil.isNotBlank(value)&& value.equals(lock)){
                // 只有持有锁，才能释放锁
                redisUtil.del(key);
            }

        }
        return "ok";
    }

     @GetMapping("/redisDemo")
    public String redisDemo(String key){
        if(RedissonUtil.getLock("RedisLock_"+key,20, TimeUnit.SECONDS)) {
            try {
                System.out.println(Thread.currentThread().getName()+"开始 ing");
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            finally {
                RedissonUtil.unlock("RedisLock_"+key);
            }
        }
        return "OK";
    }

}
